package com.puppy.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Slf4j
//@Aspect
@Order(1) // 设置切面优先级，值越小，优先级越高.多个切面同时匹配目标，则执行优先级高的切面先使用befor最先，after最后
@Component
public class MyAspect {
    // 切面 - 切入点 - 统一抽取切入点表达式
    @Pointcut("execution(* com.puppy.service.*.*(Integer))")
    public void pointCut() {
    }

    // 前置通知 - 目标方法运行之前
    @Before("execution(public void com.puppy.service.impl.DeptServiceImpl.deleteById(Integer))")
    public void before() {
        log.info("before");
    }

    //环绕通知 - 目标方法运行之前和之后，运行过程中抛出异常也会执行此通知
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        log.info("around before");
        Object obj = pjp.proceed();
        log.info("around after");
        return obj;
    }

    // 后置通知 - 目标方法运行之后，不管是正常结束还是异常结束都会执行此通知
//    @After("pointCut()")
    @After("@annotation(com.puppy.anno.LogOperation)")
    public void after(JoinPoint joinPoint) {
        log.info("after");
        //1.获得目标对象
        Object target = joinPoint.getTarget();
        log.info("target:{}", target);
        //2.获得目标类
        Class<?> targetClass = joinPoint.getTarget().getClass();
        log.info("targetClass:{}", targetClass);
        log.info("targetClass.getName():{}", targetClass.getName());
        //3.获得目标方法
        String methodName = joinPoint.getSignature().getName();
        log.info("methodName:{}", methodName);
        //4.获得目标方法参数
        Object[] args = joinPoint.getArgs();
        log.info("args:{}", Arrays.toString(args));
    }

    // 异常通知 - 目标方法抛出异常时
    @AfterThrowing("pointCut()")
    public void afterThrowing() {
        log.info("afterThrowing");
    }

    // 最终通知 - 目标方法正常结束运行之后，异常结束不会执行此通知
    @AfterReturning("pointCut()")
    public void afterReturning() {
        log.info("afterReturning");
    }

}
